#include "bsp_es8311.h"
#include "wav_head.h"
#include <string.h>
#define TAG "bsp_es8311"
#define I2S_MCK_PIN 38
#define I2S_BCK_PIN 14
#define I2S_DATA_WS_PIN 13
#define I2S_DATA_OUT_PIN 45
#define I2S_DATA_IN_PIN -1

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
static void ut_set_i2s_mode(i2s_comm_mode_t out_mode, i2s_comm_mode_t in_mode)
{
   i2s_in_mode = in_mode;
   i2s_out_mode = out_mode;
}

static void ut_clr_i2s_mode(void)
{
   i2s_in_mode = I2S_COMM_MODE_STD;
   i2s_out_mode = I2S_COMM_MODE_STD;
}
#endif

static int ut_i2s_init(uint8_t port)
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
   if (port >= I2S_MAX_KEEP)
   {
      return -1;
   }
   // Already installed
   if (i2s_keep[port])
   {
      return 0;
   }
   i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
   i2s_std_config_t std_cfg = {
       .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
       .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO),
       .gpio_cfg = {
           .mclk = I2S_MCK_PIN,
           .bclk = I2S_BCK_PIN,
           .ws = I2S_DATA_WS_PIN,
           .dout = I2S_DATA_OUT_PIN,
           .din = I2S_DATA_IN_PIN,
       },
   };
   i2s_keep[port] = (i2s_keep_t *)calloc(1, sizeof(i2s_keep_t));
   if (i2s_keep[port] == NULL)
   {
      return -1;
   }
#if SOC_I2S_SUPPORTS_TDM
   i2s_tdm_slot_mask_t slot_mask = I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3;
   i2s_tdm_config_t tdm_cfg = {
       .slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO, slot_mask),
       .clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(16000),
       .gpio_cfg = {
           .mclk = I2S_MCK_PIN,
           .bclk = I2S_BCK_PIN,
           .ws = I2S_DATA_WS_PIN,
           .dout = I2S_DATA_OUT_PIN,
           .din = I2S_DATA_IN_PIN,
       },
   };
   tdm_cfg.slot_cfg.total_slot = 4;
#endif
   int ret = i2s_new_channel(&chan_cfg, &i2s_keep[port]->tx_handle, &i2s_keep[port]->rx_handle);
   TEST_ESP_OK(ret);
   if (i2s_out_mode == I2S_COMM_MODE_STD)
   {
      ret = i2s_channel_init_std_mode(i2s_keep[port]->tx_handle, &std_cfg);
   }
#if SOC_I2S_SUPPORTS_TDM
   else if (i2s_out_mode == I2S_COMM_MODE_TDM)
   {
      ret = i2s_channel_init_tdm_mode(i2s_keep[port]->tx_handle, &tdm_cfg);
   }
#endif
   TEST_ESP_OK(ret);
   if (i2s_in_mode == I2S_COMM_MODE_STD)
   {
      ret = i2s_channel_init_std_mode(i2s_keep[port]->rx_handle, &std_cfg);
   }
#if SOC_I2S_SUPPORTS_TDM
   else if (i2s_in_mode == I2S_COMM_MODE_TDM)
   {
      ret = i2s_channel_init_tdm_mode(i2s_keep[port]->rx_handle, &tdm_cfg);
   }
#endif
   TEST_ESP_OK(ret);
   // For tx master using duplex mode
   i2s_channel_enable(i2s_keep[port]->tx_handle);
#else
   i2s_config_t i2s_config = {
       .mode = (i2s_mode_t)(I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER),
       .sample_rate = 44100,
       .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
       .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
       .communication_format = I2S_COMM_FORMAT_STAND_I2S,
       .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2 | ESP_INTR_FLAG_IRAM,
       .dma_buf_count = 2,
       .dma_buf_len = 128,
       .use_apll = true,
       .tx_desc_auto_clear = true,
   };
   int ret = i2s_driver_install(port, &i2s_config, 0, NULL);
   i2s_pin_config_t i2s_pin_cfg = {
       .mck_io_num = TEST_BOARD_I2S_MCK_PIN,
       .bck_io_num = TEST_BOARD_I2S_BCK_PIN,
       .ws_io_num = TEST_BOARD_I2S_DATA_WS_PIN,
       .data_out_num = TEST_BOARD_I2S_DATA_OUT_PIN,
       .data_in_num = TEST_BOARD_I2S_DATA_IN_PIN,
   };
   i2s_set_pin(port, &i2s_pin_cfg);
#endif
   return ret;
}

void codec_max_sample(uint8_t *data, int size, int *max_value, int *min_value)
{
   int16_t *s = (int16_t *)data;
   size >>= 1;
   int i = 1, max, min;
   max = min = s[0];
   while (i < size)
   {
      if (s[i] > max)
      {
         max = s[i];
      }
      else if (s[i] < min)
      {
         min = s[i];
      }
      i++;
   }
   *max_value = max;
   *min_value = min;
}
void codec_init(void)
{
   esp_err_t ret;
   i2c_init();
   ut_i2s_init(0);
   // Do initialize of related interface: data_if, ctrl_if and gpio_if
   audio_codec_i2s_cfg_t i2s_cfg = {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
       .rx_handle = i2s_keep[0]->rx_handle,
       .tx_handle = i2s_keep[0]->tx_handle,
#endif
   };

   const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg);
   TEST_ASSERT_NOT_NULL(data_if);

   audio_codec_i2c_cfg_t i2c_cfg = {.port = I2C_PORT, .addr = ES8311_CODEC_DEFAULT_ADDR}; // ES8311_CODEC_DEFAULT_ADDR 0x30 ESP 库会右移1位 0x18 8311物理地址0x18
#ifdef USE_IDF_I2C_MASTER
   i2c_cfg.bus_handle = i2c_bus_handle;
#endif

   // i2c_master_transmit_receive(i2c_cfg.bus_handle, addr_data, addr_len, data, data_len, DEFAULT_I2C_TRANS_TIMEOUT);

   const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
   TEST_ASSERT_NOT_NULL(out_ctrl_if);
   ESP_LOGI(TAG, "i2c_config ok.");

   const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();
   ESP_LOGI(TAG, "gpio_if ok.");
   TEST_ASSERT_NOT_NULL(gpio_if);
   // New output codec interface
   es8311_codec_cfg_t es8311_cfg = {
       .codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC,
       .ctrl_if = out_ctrl_if,
       .gpio_if = gpio_if,
       .pa_pin = -1,
       .use_mclk = true,
   };

   const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);
   TEST_ASSERT_NOT_NULL(out_codec_if);

   ESP_LOGI(TAG, "out_codec_if ok.");

   // New output codec device
   esp_codec_dev_cfg_t dev_cfg = {
       .codec_if = out_codec_if,
       .data_if = data_if,
       .dev_type = ESP_CODEC_DEV_TYPE_OUT,
   };
   esp_codec_dev_handle_t play_dev = esp_codec_dev_new(&dev_cfg);
   TEST_ASSERT_NOT_NULL(play_dev);

   ESP_LOGI(TAG, "play_dev ok.");

   ret = esp_codec_dev_set_out_vol(play_dev, 60.0);
   TEST_ESP_OK(ret);

   esp_codec_dev_sample_info_t fs = {
       .sample_rate = 48000,
       .channel = 2,
       .bits_per_sample = 16,
   };
   ret = esp_codec_dev_open(play_dev, &fs);
   TEST_ESP_OK(ret);

   extern const unsigned char wavdata[403432];
   wav_head wav;
   memcpy(&wav, wavdata, sizeof(wav_head));
   wave_head_parse(&wav);

   
   int limit_size = 10 * fs.sample_rate * fs.channel * (fs.bits_per_sample >> 3);
   int got_size = 0;
   pa_en(1);

   ret = esp_codec_dev_write(play_dev, &wavdata[44], 403432-44);
   TEST_ESP_OK(ret);
  // int max_sample, min_sample;
  // codec_max_sample(data, 512, &max_sample, &min_sample);
   // Verify recording data not constant
   //TEST_ASSERT(max_sample > min_sample);
 
   vTaskDelay(500);
}